/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
#include "oled.h"
#include<stdio.h>
#include "math.h"
#include "stm32_dsp.h"
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "i2c.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#define  NPT  256             /* 采样点数 */
uint32_t lBufInArray[NPT];    /* FFT 运算的输入数组 */
uint32_t lBufOutArray[NPT/2]; /* FFT 运算的输出数组 */
uint32_t lBufMagArray[NPT/2]; /* 各次谐波的幅值 */
typedef struct {
    struct {
        signed short lBufOutArray[NPT / 2];
        unsigned long lBufMagArray[NPT / 2];
    } freqency;
} Miniscope;
Miniscope miniscope;

#define SAMPLE_FREQ 5000
#define ADC_DMA_BUF_SIZE        1          /* ADC DMA采集 BUF大小, 应等于ADC通道数的整数倍 */
uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE];   /* ADC DMA BUF */
uint16_t ADC_DATA=10;

uint32_t sum = 0;
uint8_t cnt = 0;
uint8_t FFT_cnt = 0;
uint8_t FFT_over = 0;
uint8_t FFT_over_Flag = 0;
#define TOP_FREQS 4  // 要提取的频率分量数量
float mainFreqs[TOP_FREQS];
unsigned long mainMags[TOP_FREQS];

#define FFT_AVG_COUNT 5  // 平均次数

// 全局变量用于存储多次FFT结果
float fft_sum[NPT/2] = {0};
uint8_t fft_avg_counter = 0;
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
void GetPowerMag(void);
void extractMainFrequencies(unsigned long *lBufMagArray, float *mainFreqs, unsigned long *mainMags);
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void show_adc_values_on_oled(void);
void show_adc_waveform(void);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_TIM2_Init();
  MX_I2C1_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  OLED_init();
  HAL_TIM_Base_Start(&htim3);//开启定时器3
  OLED_operate_gram(PEN_CLEAR);//清缓存
  OLED_show_string(0,5,(uint8_t*)"Open");
  OLED_refresh_gram();//全局刷新

  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)g_adc_dma_buf, ADC_DMA_BUF_SIZE);
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      // OLED显示（示例）
      OLED_operate_gram(PEN_CLEAR);//清缓存
      char buffer[32];
      for (uint8_t i = 0; i < TOP_FREQS; i++) {
          snprintf(buffer, sizeof(buffer), "F%d:%4dHz %4d",
                   i,
                   (uint32_t)mainFreqs[i],
                   (uint32_t)mainMags[i]);
          OLED_show_string(i , 1, buffer);
      }
      //OLED_show_floatnum(4, 0, FFT_over_cnt, 0);
//      OLED_show_floatnum(2, 0, FFT_cnt, 0);
      OLED_refresh_gram();//全局刷新
      HAL_Delay(500);
//      OLED_operate_gram(PEN_CLEAR);//清缓存
//      OLED_show_string(0,5,(uint8_t*)"show string");
//      OLED_show_floatnum(2, 12, ADC_DATA, 0);
//      OLED_refresh_gram();//全局刷新
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc==&hadc1)
    {

        if(cnt<=10)
        {
            sum += g_adc_dma_buf[0];
            cnt++;
        }
        else
        {
            ADC_DATA = (sum / 10);
            cnt = 0;
            sum = 0;
            if(FFT_cnt<=254)
            {
                lBufInArray[FFT_cnt] = ADC_DATA;
                FFT_cnt++;
            }
            else
            {
                //FFT_over_cnt++;
                cr4_fft_256_stm32(lBufOutArray, lBufInArray, NPT);
                for(int i = 0; i < NPT/2; i++) {
                    miniscope.freqency.lBufOutArray[i] = lBufOutArray[i];
                }
                GetPowerMag();
                extractMainFrequencies(miniscope.freqency.lBufMagArray, mainFreqs, mainMags);
                FFT_cnt = 0;
            }
        }
    }
}
void GetPowerMag(void)
{
    signed short lX, lY;
    float X, Y, Mag;
    unsigned short i;

    for(i = 0; i < NPT/2; i++)
    {
        lX = (miniscope.freqency.lBufOutArray[i] << 16) >> 16;
        lY = (miniscope.freqency.lBufOutArray[i] >> 16);

        X = NPT * ((float)lX) / 32768;
        Y = NPT * ((float)lY) / 32768;
        Mag = sqrt(X * X + Y * Y) * 1.0 / NPT;

        if(i == 0)
            miniscope.freqency.lBufMagArray[i] = (unsigned long)(Mag * 32768);
        else
            miniscope.freqency.lBufMagArray[i] = (unsigned long)(Mag * 65536);
    }
}
float freq(int i) {
    return (float)i * SAMPLE_FREQ / NPT;
}

void extractMainFrequencies(unsigned long *lBufMagArray, float *mainFreqs, unsigned long *mainMags)
{
    float mag[NPT / 2];
    int indices[NPT / 2];

    // 初始化数组（跳过直流分量i=0）
    for (int i = 1; i < NPT/2; i++) {  // 从1开始，跳过0Hz
        mag[i] = (float)lBufMagArray[i] / 32768.0;
        indices[i] = i;
    }

    // 对幅度进行排序（从大到小），跳过直流分量
    for (int i = 1; i < NPT/2 - 1; i++) {  // i从1开始
        for (int j = i + 1; j < NPT/2; j++) {
            if (mag[i] < mag[j]) {
                // 交换幅度
                float tempMag = mag[i];
                mag[i] = mag[j];
                mag[j] = tempMag;

                // 交换索引
                int tempIdx = indices[i];
                indices[i] = indices[j];
                indices[j] = tempIdx;
            }
        }
    }

    // 提取前TOP_FREQS个主要频率（跳过直流分量）
    for (int i = 0; i < TOP_FREQS; i++) {
        int idx = indices[i + 1];  // i+1跳过排序后的第一个元素（原i=1）
        mainFreqs[i] = freq(idx);  // freq()需要根据索引计算实际频率
        mainMags[i] = (unsigned long)(mag[i + 1] * 32768);
    }
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
